package api

import (
	"context"
	"encoding/json"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"go.uber.org/zap"
	"math/rand"
	"net/http"
	"strconv"
	"time"
	"web/user/forms"
	"web/user/global"
)

// 生成width长度的短信验证码
func GenerateSmsCode(width int) string {
	rand.Seed(time.Now().UnixNano())

	s := make([]byte, 0, width)
	for i := 0; i < width; i++ {
		s = append(s, strconv.Itoa(rand.Intn(10))...)
	}
	return string(s)
}

// 请求短信验证码服务的handler
func SendSms(ctx *gin.Context) {
	// 表单验证
	sendSmsForm := new(forms.SendSmsForm)
	if err := ctx.ShouldBind(sendSmsForm); err != nil {
		HandleValidatorError(ctx, err)
		return
	}

	client, err := dysmsapi.NewClientWithAccessKey("cn-beijing", global.ServerConfig.AliSmsInfo.ApiKey, global.ServerConfig.AliSmsInfo.ApiSecret)
	if err != nil {
		zap.S().Error("短信服务出错，请检查 AccessKey 是否可用")
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "内部错误",
		})
		return
	}
	// 随机生成短信验证码
	smsCode := GenerateSmsCode(6)
	zap.S().Debug("短信验证码:", smsCode)

	request := requests.NewCommonRequest()
	request.Method = "POST"
	// https | http
	request.Scheme = "https"
	request.Domain = "dysmsapi.aliyuncs.com"
	request.Version = "2017-05-25"
	request.ApiName = "SendSms"
	request.QueryParams["RegionId"] = "cn-beijing"
	// 接收短信的手机号码
	request.QueryParams["PhoneNumbers"] = sendSmsForm.Mobile
	// 阿里云验证过的项目名 自己设置
	request.QueryParams["SignName"] = global.ServerConfig.AliSmsInfo.SignName
	// 阿里云的短信模板号 自己设置
	request.QueryParams["TemplateCode"] = global.ServerConfig.AliSmsInfo.TemplateCode
	// 短信模板中的验证码内容 自己生成   之前试过直接返回，但是失败，加上code成功。
	request.QueryParams["TemplateParam"] = "{\"code\":" + smsCode + "}"

	response, err := client.ProcessCommonRequest(request)
	if err != nil {
		zap.S().Error("ali ecs client failed, err:%s", err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "内部错误",
		})
		return
	}

	var message struct {
		Message   string
		RequestId string
		BizId     string
		Code      string
	}

	json.Unmarshal(response.GetHttpContentBytes(), &message)
	if message.Message != "OK" {
		zap.S().Error("短信服务出错:", response.String())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "内部错误",
		})
		return
	}

	// 将手机验证码保存到redis
	redisAddr := global.ServerConfig.RedisInfo.Host + ":" + strconv.Itoa(global.ServerConfig.RedisInfo.Port)
	zap.S().Debug("redisAddr:", redisAddr)
	rdb := redis.NewClient(&redis.Options{
		Addr: redisAddr,
	})
	if _, err = rdb.Ping(ctx).Result(); err != nil {
		zap.S().Errorw("redis连接出错", "连接地址", redisAddr)
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "内部错误",
		})
		return
	}

	// 最后一个参数是记录的过期时间
	res := rdb.Set(context.Background(), "sms_code_"+sendSmsForm.Mobile, smsCode, time.Minute*5)
	if res.Err() != nil {
		zap.S().Errorw("执行redis命令出错:", res.Err())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "内部错误",
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"msg": "发送成功",
	})
	return
}
